#include "timer.h"

#include <linux/list.h>
#include <stdbool.h>
#include <stm32f1xx.h>

#include "log.h"
#include "task.h"
#include "types.h"
#include "utils.h"

volatile unsigned long jiffies = 0;

static HLIST_HEAD(s_timer_list);  // 按照到期时间排序

void timer_free(struct TIMER *timer) {
    struct TIMER *node;
    timer->flags = 0;
    hlist_for_each_entry(node, &s_timer_list, entry) {
        if (node == timer) {
            hlist_del_init(&node->entry);
            break;
        }
    }
}

void timer_init(struct TIMER *timer, FIFO32Type *fifo, unsigned int data) {
    timer->fifo = fifo;
    timer->data = data;
    INIT_HLIST_NODE(&timer->entry);
}

void timer_settime(struct TIMER *timer, unsigned long timeout) {
    int e;
    timer->expires = timeout;

    // 操作s_timer_list需要关中断，防止并行操作
    io_cli();
    // 按照到期时间排序插入
    struct TIMER *node;
    struct TIMER *prev = NULL;  // 记录要插入的节点前一个的节点

    hlist_for_each_entry(node, &s_timer_list, entry) {
        if (node->expires > timer->expires) {
            break;
        }
        prev = node;
    }
    if (prev == NULL) {
        // 没有前一个节点，说明要插入到第一个
        // 1. 有节点，但是都不满足条件，插入最前面
        // 2. 没有节点，直接插入最前面
        hlist_add_head(&timer->entry, &s_timer_list);
    } else {
        // 有前一个节点，插入到前一个节点后面
        hlist_add_behind(&timer->entry, &prev->entry);
    }

    // 恢复中断
    io_sti();
}

static void timer_handler(void) {
    ++jiffies;
    struct TIMER *node;
    struct hlist_node *n;
    bool ts = false;
    hlist_for_each_entry_safe(node, n, &s_timer_list, entry) {
        if (node->expires <= jiffies) {
            hlist_del_init(&node->entry);
            if (node == &g_task_timer) {
                ts = true;
            } else {
                fifo32_put(node->fifo, node->data);
            }
        } else {
            break;
        }
    }

    if (ts) {
        //     taskswitch();
    }
}

/**
 * @brief  Period elapsed callback in non-blocking mode
 * @param  htim TIM handle
 * @retval None
 */
void HAL_IncTick() {
    // 还原原始调用
    uwTick += uwTickFreq;
    // 调用定时器处理函数
    timer_handler();
}
